package com.cqvip.innocence.project.controller.admin;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cqvip.innocence.common.annotation.Log;
import com.cqvip.innocence.common.util.encryption.SM2Util;
import com.cqvip.innocence.common.util.html.IpUtils;
import com.cqvip.innocence.common.util.html.ServletUtils;
import com.cqvip.innocence.framework.security.SecurityUtils;
import com.cqvip.innocence.common.util.file.FileUtil;
import com.cqvip.innocence.framework.jwt.dto.LoginAdmin;
import com.cqvip.innocence.framework.jwt.service.AdminTokenService;
import com.cqvip.innocence.project.controller.AbstractController;
import com.cqvip.innocence.project.model.dto.AdminRoleView;
import com.cqvip.innocence.project.model.dto.JsonResult;
import com.cqvip.innocence.project.model.entity.*;
import com.cqvip.innocence.project.model.enums.BusinessStatus;
import com.cqvip.innocence.project.model.enums.BusinessType;
import com.cqvip.innocence.project.service.*;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.cqvip.innocence.common.util.file.FileUtil.DIRPATHBASE;


/**
 * @ClassName AdminController
 * @Description 管理员控制层
 * @Author Innocence
 * @Date 2020/7/13
 * @Version 1.0
 */
@RestController
@RequestMapping("/${base-url.system}/admin/")
@Api(tags = "管理员控制层接口")
public class AdminController extends AbstractController {
    @Autowired
    OperLogService operLogService;
    @Autowired
    private AdminService adminService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private AdminRoleService adminRoleService;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private AdminTokenService tokenService;

    @javax.annotation.Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private CapchaCodeGen capchaCodeGen;


    /**
     * 设置管理员登录日志
     *
     * @param name
     * @return void
     * @author Innocence
     * @date 2022/5/31
     */
    protected void setLoginLog(String name, Long id, JsonResult jsonResult) {
        OperLog log = new OperLog();
        log.setIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
        log.setMessage("管理员登录");
        log.setMethod("com.cqvip.innocence.project.controller.admin.AdminController.adminLogin()");
        Boolean success = jsonResult.getSuccess();
        if (success == true) {
            log.setResponseParam(JSON.toJSONString(jsonResult));
            log.setStatus(BusinessStatus.SUCCESS.ordinal());
        } else {
            log.setResponseParam(JSON.toJSONString(jsonResult));
            log.setStatus(BusinessStatus.FAIL.ordinal());
            log.setErrorMsg(StrUtil.isNotBlank(jsonResult.getMsg()) ? jsonResult.getMsg() : "");
        }
        log.setRequestMethod(ServletUtils.getRequest().getMethod());
        // 保存数据库
        log.setCreateTime(LocalDateTime.now());
        log.setAdminName(name);
        log.setType(BusinessType.SELECT);
        if (null != id) log.setAdminId(id);
        operLogService.save(log);
    }

    @PostMapping("login")
    @ApiOperation("后台管理员登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "登录用户名", dataType = "String", required = true),
            @ApiImplicitParam(name = "passWord", value = "密码，前端通过国密2加密后传输", dataType = "String", required = true),
            @ApiImplicitParam(name = "code", value = "验证码", dataType = "String", required = true),
            @ApiImplicitParam(name = "uuid", value = "验证码uuid", dataType = "String", required = true),
    })
    public JsonResult adminLogin(String name, String passWord, String code, String uuid) {
        //验证码
        JsonResult jsonResult = capchaCodeGen.checkCapcha(code, uuid);
        if (null != jsonResult) return jsonResult;
        if (StringUtils.isBlank(name) || StringUtils.isBlank(passWord)) {
            JsonResult result = JsonResult.Get(false, "用户名或密码不能为空");
            setLoginLog(name, null, result);
            return result;
        }
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(name, SM2Util.decrypt(passWord, SM2Util.PRIAVTEKEY)));
        } catch (Exception e) {
            e.printStackTrace();
            JsonResult result;
            if (e instanceof BadCredentialsException) {
                result = JsonResult.Get(false, "用户名或密码错误");
            } else {
                result = JsonResult.Get(false, e.getMessage());
            }
            setLoginLog(name, null, result);
            return result;
        }

        LoginAdmin loginAdmin = (LoginAdmin) authentication.getPrincipal();
        JsonResult res = JsonResult.Get();
        setLoginLog(name, loginAdmin.getAdminUser().getId(), res);
        LocalDateTime recentTime = loginAdmin.getAdminUser().getRecentTime();
        // 生成token
        String adminToken = tokenService.createAdminToken(loginAdmin);
        if (loginAdmin.getAdminUser().getRecentTime() == null) {
            loginAdmin.getAdminUser().setRecentTime(LocalDateTime.now());
        }
        if (!loginAdmin.getAdminUser().getRecentTime().toLocalDate().toString().equals(LocalDateTime.now().toLocalDate().toString())) {
            loginAdmin.getAdminUser().setRecentTime(LocalDateTime.now());
            adminService.updateById(loginAdmin.getAdminUser());
        }
        loginAdmin.getAdminUser().setPassWord("");
        res.put("token", adminToken);
        loginAdmin.getAdminUser().setRecentTime(recentTime);
        res.put("admin", loginAdmin.getAdminUser());
        return res;
    }

    @GetMapping("getInfo")
    @ApiOperation("获取当前登录管理员信息，包括角色，权限")
    public JsonResult getInfo() {
        JsonResult result = JsonResult.Get();
        Admin loginAdmin = tokenService.getLoginAdmin().getAdminUser();
        Admin admin = adminService.getById(loginAdmin.getId());
        if (StrUtil.isNotBlank(admin.getAvatar())) {
            admin.setAvatar(admin.getAvatar().substring(admin.getAvatar().lastIndexOf("upload") - 1));
        }
        if (null == admin) {
            result.setSuccess(false);
            return result;
        }
        List<String> roleList = new ArrayList<>(),
                permissionLists = new ArrayList<>();
        List<Role> roles = roleService.getRolesByAdmin(admin);
        for (Role role : roles) {
            roleList.add(role.getName());
            List<Resource> resourcesByRoleId = resourceService.getResourcesByRoleId(role);
            for (Resource resource : resourcesByRoleId) {
                permissionLists.add(resource.getPermission());
            }
        }
        List<String> collect = permissionLists.stream().distinct().collect(Collectors.toList());
        result.setSuccess(true);
        result.put("admin", admin);
        result.put("roles", roleList);
        result.put("permissions", collect);
        return result;
    }

    @PostMapping("logout")
    @ApiOperation("管理员退出登录")
    public JsonResult adminLogout(HttpServletRequest request) {
        LoginAdmin loginAdmin = tokenService.getLoginAdmin(tokenService.getTokenFromRequest(request));
        if (null != loginAdmin) {
            tokenService.delLoginAdmin(tokenService.getTokenFromRequest(request));
        }
        return JsonResult.Get();
    }

    @GetMapping("getAdmins")
    @ApiOperation("根据用户名或角色名获取管理员列表,包括角色和权限id")
    public JsonResult getAdminsList(AdminRoleView adminRoleView) {
        Page page = getPageParams();
        Page<AdminRoleView> list = adminService.getAdminsList(page, adminRoleView);
        return JsonResult.Get("page", list);
    }

    @GetMapping("getAllAdmins")
    @ApiOperation("获取所有管理员列表")
    public JsonResult getAllAdmins() {
        return JsonResult.Get().putList(adminService.list());
    }


    @PostMapping("changeAdminLocked")
    @ApiOperation("修改管理员锁定状态")
    @Log(title = "修改管理员锁定状态", businessType = BusinessType.UPDATE)
    @PreAuthorize("hasAnyAuthority('admin:adminUser:*')")
    public JsonResult changeAdminLocked(Admin admin) {
        UpdateWrapper<Admin> set = new UpdateWrapper<>();
        set.eq("id", admin.getId()).set("locked", admin.getLocked());
        adminService.update(set);
        return JsonResult.Get();
    }

    @PostMapping("resetPassWord")
    @ApiOperation("管理员重置密码")
    @Log(title = "管理员重置密码", businessType = BusinessType.UPDATE)
    @PreAuthorize("hasAnyAuthority('admin:adminUser:*')")
    public JsonResult resetPassWord(Admin admin) {
        UpdateWrapper<Admin> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", admin.getId()).set("pass_word", SecurityUtils.encryptPassword(admin.getPassWord()));
        adminService.update(wrapper);
        return JsonResult.Get();
    }

    @PostMapping("addOrEdit")
    @ApiOperation("管理员的新增编辑")
    @PreAuthorize("hasAnyAuthority('admin:manager:addOrEdit')")
    @Log(title = "管理员的新增编辑", businessType = BusinessType.SAVE_OR_UPDATE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "admin.passWord", value = "密码，为空时不修改，不为空时用国密2加密后上传", dataTypeClass = String.class),
            @ApiImplicitParam(name = "admin.id", value = "用户id，为空时表示修改当前用户，不为空时表示新增", dataTypeClass = Long.class),
    })
    public JsonResult addOrEdit(@RequestBody Admin adminUser) {
        if (null == adminUser.getId() && StrUtil.isBlank(adminUser.getName())) {
            return JsonResult.Get(false, "管理员账户不能为空！");
        }
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Admin::getName, adminUser.getName())
                .ne(adminUser.getId() != null, Admin::getId, adminUser.getId());
        List<Admin> admins = adminService.list(wrapper);
        if (admins.size() > 0) {
            return JsonResult.Get(false, "用户名已被使用!");
        }
        if (StrUtil.isNotBlank(adminUser.getPassWord())) {
            String decrypt = SM2Util.decrypt(adminUser.getPassWord(), SM2Util.PRIAVTEKEY);
            adminUser.setPassWord(SecurityUtils.encryptPassword(decrypt));
        } else {
            adminUser.setPassWord(null);
        }
        adminService.saveOrUpdate(adminUser);
        if (!adminUser.getRoleIds().isEmpty() && adminUser.getRoleIds().size() > 0) {
            LambdaQueryWrapper<AdminRole> lambda = new QueryWrapper<AdminRole>().lambda();
            lambda.eq(AdminRole::getAdminId, adminUser.getId());
            adminRoleService.remove(lambda);
            List<AdminRole> adminRoles = new ArrayList<>();
            for (Long id : adminUser.getRoleIds()) {
                AdminRole adminRole = new AdminRole();
                adminRole.setAdminId(adminUser.getId());
                adminRole.setRoleId(id);
                adminRoles.add(adminRole);
            }
            adminRoleService.saveBatch(adminRoles);
        }
        return JsonResult.Get(true);
    }

    @PostMapping("deleteByIds")
    @ApiOperation("根据ID批量删除管理员,同时删除其角色关系;参数名：deleteIds，含义：需要删除的管理员id集合")
    @PreAuthorize("hasAnyAuthority('admin:manager:delete')")
    @Log(title = "根据ID批量删除管理员和及其角色关系", businessType = BusinessType.DELETE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deleteIds", value = "管理员id数组", required = true)
    })
    public JsonResult deleteByIds(@RequestBody List<Long> deleteIds) {
        LambdaQueryWrapper<AdminRole> wrapper = new LambdaQueryWrapper<>();
        for (Long id : deleteIds) {
            wrapper.eq(AdminRole::getAdminId, id);
            adminRoleService.remove(wrapper);
        }
        adminService.removeByIds(deleteIds);
        return JsonResult.Get(true);
    }

    @PostMapping("avatar")
    @ApiOperation("上传头像")
    @Log(title = "上传头像", businessType = BusinessType.UPDATE)
    public JsonResult avatar(MultipartFile file) throws IOException {
        Admin admin = tokenService.getLoginAdmin().getAdminUser();
        FileUtil fileUtil = new FileUtil();
        String path = fileUtil.getPath(DIRPATHBASE);
        String filePath = path + File.separator + admin.getId() + ".png";
        fileUtil.bytesToFile(file.getBytes(), filePath);
        String savePath = filePath.substring(filePath.indexOf("upload") - 1);
        admin.setAvatar(filePath);
        LambdaUpdateWrapper<Admin> wrapper = new UpdateWrapper<Admin>().lambda();
        wrapper.eq(Admin::getId, admin.getId()).set(Admin::getAvatar, savePath);
        adminService.update(wrapper);
        JsonResult get = JsonResult.Get(true);
        get.put("path", savePath);
        return get;
    }

    @PostMapping("updateMyselfPassword")
    @ApiOperation("管理员修改自己的密码")
    public JsonResult updateMyselfPassword(String oldPassword, String newPassword) {
        Admin adminUser = SecurityUtils.getLoginAdmin().getAdminUser();
        Admin admin = adminService.getById(adminUser.getId());
        boolean b = SecurityUtils.matchesPassword(SM2Util.decrypt(oldPassword, SM2Util.PRIAVTEKEY), admin.getPassWord());
        if (!b) {
            return JsonResult.Get(false, "原密码错误，校验失败！");
        }
        String newPass = SecurityUtils.encryptPassword(SM2Util.decrypt(newPassword, SM2Util.PRIAVTEKEY));
        LambdaUpdateWrapper<Admin> set = new UpdateWrapper<Admin>()
                .lambda()
                .eq(Admin::getId, admin.getId())
                .set(Admin::getPassWord, newPass);
        boolean update = adminService.update(set);
        return JsonResult.Get(update);
    }

    @PostMapping("updateInfoWithOutOther")
    @ApiOperation("更新自身基础信息，不处理密码和权限关系")
    public JsonResult updateInfoWithOutRole(Admin user) {
        Admin admin = adminService.getById(user.getId());
        user.setPassWord(admin.getPassWord());
        boolean update = adminService.saveOrUpdate(user);
        return JsonResult.Get(update);
    }

}
